﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Socket网络编程Service
{
    public partial class Form1 : Form
    {
        // 下面是我的私有字段
        // 所有客户机端口用于通信的Socket
        Dictionary<string, Socket> _socketComDic = new Dictionary<string, Socket>();

        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 开启服务器对指定端口的监听
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_OpenMonitor_Click(object sender, EventArgs e)
        {
            Socket monitorSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ip = IPAddress.Parse(textBox_IP.Text);
            //IPAddress ip = IPAddress.Any;
            IPEndPoint port = new IPEndPoint(ip, int.Parse(textBox_Port.Text));
            monitorSocket.Bind(port);

            monitorSocket.Listen(10);

            ShowLog("监听成功");

            Thread listenThread = new Thread(ListenTask);
            listenThread.IsBackground = true;
            listenThread.Name = "为新建连接创建通信的Socekt";
            listenThread.Start(monitorSocket);

            ShowLog("创建了负责监听活动客户端的线程");
            ShowLog("当前线程总数为" + Process.GetCurrentProcess().Threads.Count.ToString());
        }


        /// <summary>
        /// 负责创建与服务器连接的通信Socket
        /// </summary>
        /// <param name="arg">监听Socekt</param>
        private void ListenTask(object arg)
        {
            Socket monitorSocket = arg as Socket;
            while (true)
            {
                Socket socketCom = monitorSocket.Accept();

                _socketComDic.Add(socketCom.RemoteEndPoint.ToString(), socketCom);
                comboBox_ClientList.Items.Add(socketCom.RemoteEndPoint.ToString());
                comboBox_ClientList.SelectedIndex = comboBox_ClientList.Items.Count - 1;

                Thread reciveThread = new Thread(ReciveTask);
                reciveThread.IsBackground = true;
                reciveThread.Name = "接收线程";
                reciveThread.Start(socketCom);

                ShowLog("创建了负责接收" + socketCom.RemoteEndPoint.ToString() + "数据的线程");
                ShowLog("当前线程总数为" + Process.GetCurrentProcess().Threads.Count.ToString());
            }
        }

        /// <summary>
        /// 服务器接收所有客户端发来的字符文本，没有做客户端区分与数据格式区分
        /// </summary>
        /// <param name="arg"></param>
        private void ReciveTask(object arg)
        {
            //try
            //{
            Socket socketCom = arg as Socket;
            List<byte> databuff = new List<byte>();
            while (true)
            {
                byte[] buff = new byte[1024*1024*5];
                // 如果连接正常，但一直无数据，那么就会一直处于读取状态不会往下面执行
                // 如果客户端正常主动关闭了连接那么就会返回0
                // 如果是由于网络等方面的原因导致连接异常断开，就会抛“客户端强迫断开了连接”异常
                int count = socketCom.Receive(buff);
                for (int i = 0; i < count; i++)
                {
                    databuff.Add(buff[i]);
                }
                if (count == 0)
                {
                    ShowLog("客户端" + socketCom.RemoteEndPoint.ToString() + "断开连接");
                    break;
                }
                if (databuff.Count >= 10)
                {
                    // 验证使用telnet导致服务器接收中文乱码，而使用自己的客户端不会产生乱码的问题
                    // 初步验证到是因为telnet的发送采用的是不阻塞IO的异步方式发送，因此其数据流并
                    // 不是一次性接收到，导致解码异常，将其添加到list里达到10个字节再解析，就能看出问题所在
                    //textBox_RX.AppendText(socketCom.RemoteEndPoint.ToString() + ":" + Encoding.GetEncoding(936).GetString(databuff.ToArray(), 0, databuff.Count) + "\r\n");
                    databuff.Clear();
                }
                textBox_RX.AppendText(socketCom.RemoteEndPoint.ToString() + ":" + Encoding.GetEncoding(936).GetString(buff, 0, count) + "\r\n");
            }

            ShowLog("请点击下方按钮获取当前进程线程数");
            // 删除通信套接字集合中的当前套接字
            _socketComDic.Remove(socketCom.RemoteEndPoint.ToString());
            // 删除通信套接字列表中的当前套接字
            comboBox_ClientList.Items.Remove(socketCom.RemoteEndPoint.ToString());
            // 断开当前通信套接字
            socketCom.Disconnect(true);
            // 关闭当前套接字释放资源
            socketCom.Close();
          
            // 中止当前套接字接收线程
            Thread.CurrentThread.Abort();
            //}
            //catch { 

            //}                                        
        }

        /// <summary>
        /// 日志打印
        /// </summary>
        /// <param name="str"></param>
        private void ShowLog(string str)
        {
            textBox_Log.AppendText(str + "\r\n");
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        /// <summary>
        /// 获取当前程序线程总数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_GetCurProThrNum_Click(object sender, EventArgs e)
        {
            ShowLog("当前线程总数为" + Process.GetCurrentProcess().Threads.Count.ToString());
        }

        /// <summary>
        /// 向指定客户机发送字符文本
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonSend_Click(object sender, EventArgs e)
        {
            if (comboBox_ClientList.Items.Count != 0)
            {
                List<byte> buffList = new List<byte>();
                byte[] newbuff = new byte[1];

                newbuff = Encoding.GetEncoding(936).GetBytes(textBox_TX.Text);

                buffList.Add(1);
                buffList.AddRange(newbuff);

                newbuff = buffList.ToArray();
                string clientport = comboBox_ClientList.SelectedItem.ToString();
                _socketComDic[clientport].Send(newbuff);
            }
            else
            {
                ShowLog("连接节点为零,请先创建连接");
            }
        }

        /// <summary>
        /// 向指定的客户机发送文件流
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_SendFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.AddExtension = true;
            ofd.InitialDirectory = ".";
            ofd.Filter = "所有文件|*.*";
            ofd.Multiselect = false;
            ofd.ShowDialog();

            textBox_FileDir.Text = ofd.FileName;
            string path = textBox_FileDir.Text.ToString();
            using (FileStream fr = new FileStream(path,FileMode.Open,FileAccess.Read))
            {
                FileInfo fi = new FileInfo(path);
                byte[] readbuff = new byte[fi.Length];
                List<byte> readBuffList = new List<byte>();
                // 第1字节是1表示传输的是文件（但这里不设计区分文件的格式，如要设计就再添加1字节）
                readBuffList.Add(2);
                fr.Read(readbuff,0,readbuff.Length);
                readBuffList.AddRange(readbuff);

                readbuff = readBuffList.ToArray();

                string clientport = comboBox_ClientList.SelectedItem.ToString();
                _socketComDic[clientport].Send(readbuff);
            }
        }

        /// <summary>
        /// 发送让选中的客户端震动的操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_Shake_Click(object sender, EventArgs e)
        {
            if (comboBox_ClientList.Items.Count != 0)
            {
                byte[] newbuff = new byte[1]{3};
               
                string clientport = comboBox_ClientList.SelectedItem.ToString();
                _socketComDic[clientport].Send(newbuff);
            }
            else
            {
                ShowLog("连接节点为零,请先创建连接");
            }
        }
    }
}
